package com.atguigu.lease.web.app.service.impl;


import com.atguigu.lease.common.constant.RedisConstant;
import com.atguigu.lease.common.exception.LeaseException;
import com.atguigu.lease.common.result.ResultCodeEnum;
import com.atguigu.lease.common.utils.JwtUtil;
import com.atguigu.lease.common.utils.VerifyCodeUtil;
import com.atguigu.lease.model.entity.UserInfo;
import com.atguigu.lease.model.enums.BaseStatus;
import com.atguigu.lease.web.app.service.LoginService;
import com.atguigu.lease.web.app.service.SmsService;
import com.atguigu.lease.web.app.service.UserInfoService;
import com.atguigu.lease.web.app.vo.user.LoginVo;
import com.atguigu.lease.web.app.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private RedisTemplate<String,String> redisTemplate ;

    @Autowired
    private SmsService smsService ;

    @Autowired
    private UserInfoService userInfoService ;

    @Override
    public void getSMSCode(String phone) {

        //1.如果手机号为空，则直接抛异常
        if(!StringUtils.hasText(phone)){
            throw new LeaseException(ResultCodeEnum.APP_LOGIN_PHONE_EMPTY);
        }

        //2.检查，防止频繁的发送验证码
        // 假设验证码是 10分钟内 有效
        // 假设验证码不允许连续发送，而是要等待60秒之后才能再次发送验证码
        String key = RedisConstant.APP_LOGIN_PREFIX+phone ;
        if(redisTemplate.hasKey(key)){
            //如果当前redis中对应的key存在，说明之前产生过验证码，而且没有超过十分钟。但是手机上可能没有收到短消息
            //因此，需要重新发送短消息。那么为了避免频繁的发送短消息，我们做一个业务规定，重复发送短消息一定是一分钟之后

            //获取这个key对应的value还剩多少秒过期(假设还剩550秒)
            Long expire = redisTemplate.getExpire(key, TimeUnit.SECONDS);
            if(RedisConstant.APP_LOGIN_CODE_TTL_SEC-expire<RedisConstant.APP_LOGIN_CODE_RESEND_TIME_SEC){
                throw new LeaseException(ResultCodeEnum.APP_SEND_SMS_TOO_OFTEN);
            }
        }

        //3.发送验证码
        String code = VerifyCodeUtil.verifyCode();
        //3-1.保存到redis中
        redisTemplate.opsForValue().set(key,code,RedisConstant.APP_LOGIN_CODE_TTL_SEC,TimeUnit.SECONDS);
        //3-2.向phone发送短消息
        smsService.sendCode(phone,code);
    }

    @Override
    public String login(LoginVo loginVo) {
        String phone = loginVo.getPhone();
        String code = loginVo.getCode();
        if(!StringUtils.hasText(phone)){
            throw new LeaseException(ResultCodeEnum.APP_LOGIN_PHONE_EMPTY);
        }
        if(!StringUtils.hasText(code)){
            throw new LeaseException(ResultCodeEnum.APP_LOGIN_CODE_EMPTY);
        }
        String key = RedisConstant.APP_LOGIN_PREFIX+phone ;
        if(!redisTemplate.hasKey(key)){
            throw new LeaseException(ResultCodeEnum.APP_LOGIN_CODE_EXPIRED);
        }
        String codeFromRedis = redisTemplate.opsForValue().get(key);
        if(!code.equals(codeFromRedis)){
            throw new LeaseException(ResultCodeEnum.APP_LOGIN_CODE_ERROR);
        }

        LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UserInfo::getPhone,phone);
        UserInfo userInfoFromDB = userInfoService.getOne(lambdaQueryWrapper);
        if(userInfoFromDB==null){
            UserInfo userInfo = UserInfo.builder().phone(phone).build();
            userInfoService.save(userInfo);
            userInfoFromDB = userInfo ;
        }else{
            if(userInfoFromDB.getStatus()== BaseStatus.DISABLE){
                throw new LeaseException(ResultCodeEnum.APP_ACCOUNT_DISABLED_ERROR);
            }
        }
        String token = JwtUtil.createToken(userInfoFromDB.getId(), userInfoFromDB.getPhone());
        return token;
    }

    @Override
    public UserInfoVo getUserInfoId(Long userId) {
        UserInfo userInfo = userInfoService.getById(userId);
        return UserInfoVo.builder().avatarUrl(userInfo.getAvatarUrl()).nickname(userInfo.getNickname()).build();
    }
}
